﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace System {
    public static partial class Extention {
        #region Split
        public static string[] Split(this string str,string separator) {
            return str.Split(new[] { separator },StringSplitOptions.None);
        }
        public static string[] Split(this string str,string separator,StringSplitOptions options) {
            return str.Split(new[] { separator },options);
        }
        #endregion
        /// <summary>
        /// 计算字符串中子串出现的次数
        /// </summary>
        /// <param name="str">字符串</param>
        /// <param name="substring">子串</param>
        /// <returns>出现的次数</returns>
        public static int SubstringCount(this string str,string substring) {
            if(str.Contains(substring)) {
                string strReplaced = str.Replace(substring,"");
                return (str.Length-strReplaced.Length)/substring.Length;
            }
            return 0;
        }
        #region 正则表达式
        /// <summary>
        /// 正则表达式
        /// </summary>
        public static bool IsMatch(this string s,string pattern) {
            if(s==null) return false;
            else return Regex.IsMatch(s,pattern);
        }
        /// <summary>
        /// 正则表达式
        /// </summary>
        public static string Match(this string s,string pattern) {
            if(s==null) return "";
            return Regex.Match(s,pattern).Value;
        }
        #endregion

        /// <summary>
        /// 转换类型
        /// </summary>
        public static T ToConvert<T>(this string s) {
            return Utils.GetObjTranNull<T>(s);
        }
        #region 字符串判断
        /// <summary>
        /// 判断URL
        /// </summary>
        public static bool IsUrl(this string str) {
            if(string.IsNullOrEmpty(str))
                return false;
            string Url = @"(http://)?([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?";
            return Regex.IsMatch(str,Url);
        }
        /// <summary>
        /// 判断是不是正确的手机号码
        /// </summary>
        public static bool IsPhoneNo(this string input) {
            if(string.IsNullOrEmpty(input))
                return false;
            if(input.Length!=11)
                return false;

            if(new Regex(@"^1[3578][01379]\d{8}$").IsMatch(input)
                ||new Regex(@"^1[34578][01256]\d{8}").IsMatch(input)
                ||new Regex(@"^(1[012345678]\d{8}|1[345678][0123456789]\d{8})$").IsMatch(input)
                )
                return true;
            return false;
        }
        #endregion


        /// <summary>
        /// 获得 当前操作系统目录分隔符的路径
        /// </summary>
        /// <param name="originalString">原始路径字符串</param>
        /// <returns></returns>
        public static string GetOSPlatformPath(this string originalString) {
            var sp = Path.DirectorySeparatorChar;
            var win = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
            return win ? originalString.Replace('/',sp) : originalString.Replace('\\',sp);
        }
        #region 文件操作
        /// <summary>
        /// 建立文件夹
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static bool CreateDir(this string name) {
            if(!Directory.Exists(name)) {
                Directory.CreateDirectory(name);
            }
            return true;
        }
        /// <summary>
        /// 返回文件是否存在
        /// </summary>
        /// <param name="filename">文件名</param>
        /// <returns>是否存在</returns>
        public static bool FileExists(this string filename) {
            return System.IO.File.Exists(filename);
        }
        public static void CreateDirectory(this string path) {
            Directory.CreateDirectory(path);
        }
        public static void WriteText(this string path,string contents) {
            File.WriteAllText(path,contents);
        }
        public static void DeleteFile(this string path) {
            if(File.Exists(path)) File.Delete(path);
        }
        #endregion
        /// <summary>
        /// 转换为MD5加密后的字符串（默认加密为32位）
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string ToMD5String(this string str) {
            MD5 md5 = MD5.Create();
            byte[] inputBytes = Encoding.UTF8.GetBytes(str);
            byte[] hashBytes = md5.ComputeHash(inputBytes);
            StringBuilder sb = new StringBuilder();
            for(int i = 0;i<hashBytes.Length;i++) {
                sb.Append(hashBytes[i].ToString("x2"));
            }
            md5.Dispose();
            return sb.ToString();
        }
        /// <summary>
        /// 将ASCII码形式的字符串转为对应字节数组
        /// 注：一个字节一个ASCII码字符
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static byte[] ToASCIIBytes(this string str) {
            return str.ToList().Select(x => (byte)x).ToArray();
        }
        #region SafeSql
        /// <summary>
        ///isInt true: 1,2,3 false: '1','2','3'
        /// </summary>
        /// <param name="str"></param>
        /// <param name="isInt"></param>
        /// <returns></returns>
        public static string ToSql(this string[] str, bool isInt)
        {
            if (isInt)
            {
                return string.Join(",", str);
            }
            else
            {
                StringBuilder idsStr = new StringBuilder();
                for (int i = 0; i < str.Length; i++)
                {
                    if (i > 0)
                    {
                        idsStr.Append(",");
                    }
                    idsStr.Append("'").Append(str[i]).Append("'");
                }
                return idsStr.ToString();
            }
        }
        /// <summary>
        ///isInt true: 1,2,3 false: '1','2','3'
        /// </summary>
        /// <param name="str"></param>
        /// <param name="isInt"></param>
        /// <returns></returns>
        public static string ToSql(this string str, bool isInt = true, string separator = ",")
        {
            if (isInt)
            {
                return string.Join(",", str);
            }
            else
            {
                string[] strarr = str.Split(new[] { separator }, StringSplitOptions.None);
                StringBuilder idsStr = new StringBuilder();
                for (int i = 0; i < strarr.Length; i++)
                {
                    if (i > 0)
                    {
                        idsStr.Append(",");
                    }
                    idsStr.Append("'").Append(strarr[i]).Append("'");
                }
                return idsStr.ToString();
            }
        }
        /// <summary>
        ///isInt true: 1,2,3 false: '1','2','3'
        /// </summary>
        public static string ToSql(this List<string> str,bool isInt) {
            if(isInt) {
                return string.Join(",",str);
            } else {
                StringBuilder idsStr = new StringBuilder();
                for(int i = 0;i<str.Count;i++) {
                    if(i>0) {
                        idsStr.Append(",");
                    }
                    idsStr.Append("'").Append(str[i]).Append("'");
                }
                return idsStr.ToString();
            }
        }

        /// <summary>
        /// 从脚本获取SQL命令 
        /// </summary>
        public static IList<string> ToSqlCommands(this string sql) {
            var commands = new List<string>();
            sql=Regex.Replace(sql,@"\\\r?\n",string.Empty);
            var batches = Regex.Split(sql,@"^\s*(GO[ \t]+[0-9]+|GO)(?:\s+|$)",RegexOptions.IgnoreCase|RegexOptions.Multiline);
            for(var i = 0;i<batches.Length;i++) {
                if(string.IsNullOrWhiteSpace(batches[i])||batches[i].StartsWith("GO",StringComparison.OrdinalIgnoreCase))
                    continue;
                var count = 1;
                if(i!=batches.Length-1&&batches[i+1].StartsWith("GO",StringComparison.OrdinalIgnoreCase)) {
                    var match = Regex.Match(batches[i+1],"([0-9]+)");
                    if(match.Success)
                        count=int.Parse(match.Value);
                }
                var builder = new StringBuilder();
                for(var j = 0;j<count;j++) {
                    builder.Append(batches[i]);
                    if(i==batches.Length-1)
                        builder.AppendLine();
                }
                commands.Add(builder.ToString());
            }
            return commands;
        }
        /// <summary>
        /// 过滤sql
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string ReplaceSql(this string str) {
            str=str.Replace("'","").Replace("--"," ").Replace(";","");
            return str;
        }
        /// <summary>
        /// 过滤查询sql
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string FilterDangerSql(this string str) {
            if(str.IsNull()) return "";
            str=str.ReplaceIgnoreCase("DELETE ","").ReplaceIgnoreCase("UPDATE ","").ReplaceIgnoreCase("INSERT ","").ReplaceIgnoreCase("DROP ","").ReplaceIgnoreCase("ALTER ","");
            return str;
        }
        /// <summary>
        /// 是否安全字符串SQL，例如包含"slect insert"等注入关键字
        /// </summary>
        public static bool IsSafeSQL(this string s) {
            bool ReturnValue = true;
            try {
                if(s.Trim()!="") {
                    string SqlStr = "exec|insert+|select+|delete|update|count|chr|mid|master+|truncate|char|declare|drop+|drop+table|creat+|create|*|iframe|script|";
                    SqlStr+="exec+|insert|delete+|update+|count(|count+|chr+|+mid(|+mid+|+master+|truncate+|char+|+char(|declare+|drop+table|creat+table";
                    string[] anySqlStr = SqlStr.Split('|');
                    foreach(string ss in anySqlStr) {
                        if(s.ToLower().IndexOf(ss)>=0) {
                            ReturnValue=false;
                            break;
                        }
                    }
                }
            } catch {
                ReturnValue=false;
            }
            return ReturnValue;
        }
        #endregion

        #region JsonConvert
        /// <summary>
        /// 将XML字符串反序列化为对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="xmlStr">XML字符串</param>
        /// <returns></returns>
        public static T XmlStrToObject<T>(this string xmlStr) {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlStr);
            string jsonJsonStr = JsonConvert.SerializeXmlNode(doc);
            return JsonConvert.DeserializeObject<T>(jsonJsonStr);
        }
        /// <summary>
        /// 将XML字符串反序列化为对象
        /// </summary>
        /// <param name="xmlStr">XML字符串</param>
        /// <returns></returns>
        public static JObject XmlStrToJObject(this string xmlStr) {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlStr);
            string jsonJsonStr = JsonConvert.SerializeXmlNode(doc);
            return JsonConvert.DeserializeObject<JObject>(jsonJsonStr);
        }
        /// <summary>
        /// 将Json字符串反序列化为对象
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="jsonStr">Json字符串</param>
        /// <returns></returns>
        public static T ToJson<T>(this string jsonStr) {
            if (jsonStr == null)
            {
                return default;
            }
            return JsonConvert.DeserializeObject<T>(jsonStr);
        }
        public static List<T> ToList<T>(this string jsonStr) {
            try {
                return string.IsNullOrEmpty(jsonStr) ? null : JsonConvert.DeserializeObject<List<T>>(jsonStr);
            } catch(Exception ex) {
                throw new Exception(ex.Message);
            }
        }
        /// <summary>
        /// 将Json字符串转为DataTable
        /// </summary>
        /// <param name="jsonStr">Json字符串</param>
        /// <returns></returns>
        public static DataTable ToDataTable(this string jsonStr) {
            return jsonStr==null ? null : JsonConvert.DeserializeObject<DataTable>(jsonStr);
        }
        /// <summary>
        /// 将Json字符串转为JObject
        /// </summary>
        /// <param name="jsonStr">Json字符串</param>
        /// <returns></returns>
        public static JObject ToJObject(this string jsonStr) {
            return jsonStr==null ? JObject.Parse("{}") : JObject.Parse(jsonStr.Replace("&nbsp;",""));
        }
        /// <summary>
        /// 将Json字符串转为JArray
        /// </summary>
        /// <param name="jsonStr">Json字符串</param>
        /// <returns></returns>
        public static JArray ToJArray(this string jsonStr) {
            return jsonStr==null ? JArray.Parse("[]") : JArray.Parse(jsonStr.Replace("&nbsp;",""));
        }
        #endregion
        /// <summary>
        /// 转为首字母大写
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static string ToFirstUpperStr(this string str) {
            return str.Substring(0,1).ToUpper()+str.Substring(1);
        }
        /// <summary>
        /// 转为首字母小写
        /// </summary>
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static string ToFirstLowerStr(this string str) {
            return str.Substring(0,1).ToLower()+str.Substring(1);
        }
        /// <summary>
        /// 转为网络终结点IPEndPoint
        /// </summary>=
        /// <param name="str">字符串</param>
        /// <returns></returns>
        public static IPEndPoint ToIPEndPoint(this string str) {
            IPEndPoint iPEndPoint = null;
            try {
                string[] strArray = str.Split(':').ToArray();
                string addr = strArray[0];
                int port = Convert.ToInt32(strArray[1]);
                iPEndPoint=new IPEndPoint(IPAddress.Parse(addr),port);
            } catch {
                iPEndPoint=null;
            }
            return iPEndPoint;
        }
        /// <summary>
        /// 将枚举类型的文本转为枚举类型
        /// </summary>
        /// <typeparam name="T">枚举类型</typeparam>
        /// <param name="enumText">枚举文本</param>
        /// <returns></returns>
        public static T ToEnum<T>(this string enumText) {
            var values = typeof(T).GetEnumValues().CastToList<T>();
            return values.Where(x => x.ToString()==enumText).FirstOrDefault();
        }
        public static void OpenProcess(this string s) {
            Process.Start(s);
        }
        public static string ExecuteDOS(this string cmd,out string error) {
            Process process = new Process();
            process.StartInfo.FileName="cmd.exe";
            process.StartInfo.UseShellExecute=false;
            process.StartInfo.RedirectStandardInput=true;
            process.StartInfo.RedirectStandardOutput=true;
            process.StartInfo.RedirectStandardError=true;
            process.StartInfo.CreateNoWindow=true;
            process.Start();
            process.StandardInput.WriteLine(cmd);
            process.StandardInput.WriteLine("exit");
            error=process.StandardError.ReadToEnd();
            return process.StandardOutput.ReadToEnd();
        }
        /// <summary>
        /// 转全角(SBC case)
        /// </summary>
        /// <param name="input">任意字符串</param>
        /// <returns>全角字符串</returns>
        public static string ToSBC(this string input) {
            char[] c = input.ToCharArray();
            for(int i = 0;i<c.Length;i++) {
                if(c[i]==32) {
                    c[i]=(char)12288;
                    continue;
                }
                if(c[i]<127)
                    c[i]=(char)(c[i]+65248);
            }
            return new string(c);
        }
        /// <summary>
        /// 转半角(DBC case)
        /// </summary>
        /// <param name="input">任意字符串</param>
        /// <returns>半角字符串</returns>
        public static string ToDBC(this string input) {
            char[] c = input.ToCharArray();
            for(int i = 0;i<c.Length;i++) {
                if(c[i]==12288) {
                    c[i]=(char)32;
                    continue;
                }
                if(c[i]>65280&&c[i]<65375)
                    c[i]=(char)(c[i]-65248);
            }
            return new string(c);
        }
        // 倒置字符串，输入"abcd123"，返回"321dcba"
        public static string Reverse(this string value) {
            char[] input = value.ToCharArray();
            char[] output = new char[value.Length];
            for(int i = 0;i<input.Length;i++)
                output[input.Length-1-i]=input[i];
            return new string(output);
        }
        #region 删除最后一个字符之后的字符
        /// <summary>
        /// 删除最后结尾的指定字符后的字符
        /// </summary>
        public static string DelLastChar(this string str,string strchar = ",") {
            return str.Substring(0,str.LastIndexOf(strchar));
        }
        /// <summary>
        /// 删除最后结尾的长度
        /// </summary>
        /// <param name="str"></param>
        /// <param name="Length"></param>
        /// <returns></returns>
        public static string DelLastLength(this string str,int Length) {
            if(string.IsNullOrEmpty(str))
                return "";
            str=str.Substring(0,str.Length-Length);
            return str;
        }
        /// <summary>
        /// 删除 注释和空行
        /// </summary>
        public static string DelNote(this string instr) {
            string m_outstr = instr.Clone() as string;
            RegexOptions options = RegexOptions.Multiline|RegexOptions.IgnoreCase;
            //删除 /* */ 注释
            m_outstr=new Regex(@"\/\/[^\n]*|\/\*([^\*^\/]*|[\*^\/*]*|[^\**\/]*)*\*+\/",options).Replace(m_outstr,string.Empty);
            //删除<!-- --> 注释：
            m_outstr=new Regex(@"<!-[\s\S]*?-->",options).Replace(m_outstr,string.Empty);
            //删除 // 注释 ://也删除了
            m_outstr=new Regex(@"[^:]//{1,2}[\s\S]*?\n",options).Replace(m_outstr,string.Empty);
            //删除 -- SQL注释 
            m_outstr=new Regex(@"[\t]*--[^>][^\n]*\n",options).Replace(m_outstr,string.Empty);
            //删除空白行
            m_outstr=new Regex(@"^\s*\n",options).Replace(m_outstr,string.Empty);
            return m_outstr;
        }
        /// <summary>
        /// 删除HTML文本中的脚本样式注释空行
        /// </summary>
        public static string DelHTML(this string instr) {
            string m_outstr = instr.Clone() as string;
            m_outstr=new Regex(@"(?m)<script[^>]*>(\w|\W)*?</script[^>]*>",RegexOptions.Multiline|RegexOptions.IgnoreCase).Replace(m_outstr,string.Empty);
            m_outstr=new Regex(@"(?m)<style[^>]*>(\w|\W)*?</style[^>]*>",RegexOptions.Multiline|RegexOptions.IgnoreCase).Replace(m_outstr,string.Empty);
            m_outstr=new Regex(@"(?m)<link[^>]*>(\w|\W)*?[^>]*>",RegexOptions.Multiline|RegexOptions.IgnoreCase).Replace(m_outstr,string.Empty);
            m_outstr=new Regex(@"<iframe[\s\S]+</iframe *>",RegexOptions.Multiline|RegexOptions.IgnoreCase).Replace(m_outstr,string.Empty);
            m_outstr=new Regex(@"<frameset[\s\S]+</frameset  *>",RegexOptions.Multiline|RegexOptions.IgnoreCase).Replace(m_outstr,string.Empty);
            m_outstr=new Regex(@"-->",RegexOptions.Multiline|RegexOptions.IgnoreCase).Replace(m_outstr,string.Empty);
            m_outstr=new Regex(@"<!--.*",RegexOptions.Multiline|RegexOptions.IgnoreCase).Replace(m_outstr,string.Empty);
            m_outstr=new Regex(@"(&nbsp;)+").Replace(m_outstr,"");
            m_outstr=new Regex(@"(\r\n\r\n)+").Replace(m_outstr,"");
            return m_outstr;
        }
        #endregion
        /// <summary>
        /// 判断字符串是否为Null、空
        /// string.IsNullOrWhiteSpace(s)
        /// </summary>
        public static bool IsNull(this string s) {
            return string.IsNullOrWhiteSpace(s);
        }
        /// <summary>
        /// 判断字符串是否不为Null、空 !string.IsNullOrWhiteSpace(s)
        /// </summary>
        public static bool NotNull(this string s) {
            return !string.IsNullOrWhiteSpace(s);
        }
        /// <summary>
        /// 去除所有空格
        /// </summary>
        public static string DelSpace(this string str) {
            if(str.IsNull()) return "";
            return str.Replace(" ","").Replace("\r","").Replace("\n","");
        }
        /// <summary>
        /// 替换字符串
        /// </summary>
        public static string ReplaceIgnoreCase(this string str,string oldString,string newString,StringComparison stringComparison = StringComparison.OrdinalIgnoreCase) {
            return str.IsNull() ? "" : str.Replace(oldString,newString,stringComparison);
        }
        /// <summary>
        /// 与字符串进行比较，忽略大小写
        /// </summary>
        /// <param name="s"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool EqualsIgnoreCase(this string s,string value) {
            return s.Equals(value,StringComparison.OrdinalIgnoreCase);
        }
        #region 检测字符串中是否包含列表中的关键词

        /// <summary>
        /// 检测字符串中是否包含列表中的关键词
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <param name="keys">关键词列表</param>
        /// <param name="ignoreCase">忽略大小写</param>
        /// <returns></returns>
        public static bool Contains(this string s,IEnumerable<string> keys,bool ignoreCase = true) {
            if(!keys.Any()||string.IsNullOrEmpty(s)) {
                return false;
            }

            if(ignoreCase) {
                return Regex.IsMatch(s,string.Join("|",keys.Select(Regex.Escape)),RegexOptions.IgnoreCase);
            }

            return Regex.IsMatch(s,string.Join("|",keys.Select(Regex.Escape)));
        }

        /// <summary>
        /// 检测字符串中是否以列表中的关键词结尾
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <param name="keys">关键词列表</param>
        /// <param name="ignoreCase">忽略大小写</param>
        /// <returns></returns>
        public static bool EndsWith(this string s,string[] keys,bool ignoreCase = true) {
            if(keys.Length==0||string.IsNullOrEmpty(s)) {
                return false;
            }

            return ignoreCase ? keys.Any(key => s.EndsWith(key,StringComparison.CurrentCultureIgnoreCase)) : keys.Any(s.EndsWith);
        }

        /// <summary>
        /// 检测字符串中是否包含列表中的关键词
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <param name="regex">关键词列表</param>
        /// <param name="ignoreCase">忽略大小写</param>
        /// <returns></returns>
        public static bool RegexMatch(this string s,string regex,bool ignoreCase = true) {
            if(string.IsNullOrEmpty(regex)||string.IsNullOrEmpty(s)) {
                return false;
            }

            if(ignoreCase) {
                return Regex.IsMatch(s,regex,RegexOptions.IgnoreCase);
            }

            return Regex.IsMatch(s,regex);
        }

        /// <summary>
        /// 检测字符串中是否包含列表中的关键词
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <param name="regex">关键词列表</param>
        /// <returns></returns>
        public static bool RegexMatch(this string s,Regex regex) => !string.IsNullOrEmpty(s)&&regex.IsMatch(s);

        /// <summary>
        /// 判断是否包含符号
        /// </summary>
        /// <param name="str"></param>
        /// <param name="symbols"></param>
        /// <returns></returns>
        public static bool ContainsSymbol(this string str,params string[] symbols) {
            return str switch {
                null => false,
                "" => false,
                _ => symbols.Any(str.Contains)
            };
        }

        #endregion 检测字符串中是否包含列表中的关键词

        /// <summary>
        /// 字符串掩码
        /// </summary>
        /// <param name="s">字符串</param>
        /// <param name="mask">掩码符</param>
        /// <returns></returns>
        public static string Mask(this string s,char mask = '*') {
            if(string.IsNullOrWhiteSpace(s?.Trim())) {
                return s;
            }
            s=s.Trim();
            string masks = mask.ToString().PadLeft(4,mask);
            return s.Length switch {
                >=11 => Regex.Replace(s,"(.{3}).*(.{4})",$"$1{masks}$2"),
                10 => Regex.Replace(s,"(.{3}).*(.{3})",$"$1{masks}$2"),
                9 => Regex.Replace(s,"(.{2}).*(.{3})",$"$1{masks}$2"),
                8 => Regex.Replace(s,"(.{2}).*(.{2})",$"$1{masks}$2"),
                7 => Regex.Replace(s,"(.{1}).*(.{2})",$"$1{masks}$2"),
                6 => Regex.Replace(s,"(.{1}).*(.{1})",$"$1{masks}$2"),
                _ => Regex.Replace(s,"(.{1}).*",$"$1{masks}")
            };
        }


        #region 权威校验身份证号码

        /// <summary>
        /// 根据GB11643-1999标准权威校验中国身份证号码的合法性
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <returns>是否匹配成功</returns>
        public static bool MatchIdentifyCard(this string s) {
            return s.Length switch {
                18 => CheckChinaID18(s),
                15 => CheckChinaID15(s),
                _ => false
            };
        }

        private static readonly string[] ChinaIDProvinceCodes = {
             "11", "12", "13", "14", "15",
             "21", "22", "23",
             "31", "32", "33", "34", "35", "36", "37",
             "41", "42", "43", "44", "45", "46",
             "50", "51", "52", "53", "54",
             "61", "62", "63", "64", "65",
             "71",
             "81", "82",
             "91"
        };

        private static bool CheckChinaID18(string ID) {
            ID=ID.ToUpper();
            Match m = Regex.Match(ID,@"\d{17}[\dX]",RegexOptions.IgnoreCase);
            if(!m.Success) {
                return false;
            }
            if(!ChinaIDProvinceCodes.Contains(ID.Substring(0,2))) {
                return false;
            }
            CultureInfo zhCN = new CultureInfo("zh-CN",true);
            if(!DateTime.TryParseExact(ID.Substring(6,8),"yyyyMMdd",zhCN,DateTimeStyles.None,out DateTime birthday)) {
                return false;
            }
            if(!birthday.In(new DateTime(1800,1,1),DateTime.Today)) {
                return false;
            }
            int[] factors = { 7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2 };
            int sum = 0;
            for(int i = 0;i<17;i++) {
                sum+=(ID[i]-'0')*factors[i];
            }
            int n = (12-sum%11)%11;
            return n<10 ? ID[17]-'0'==n : ID[17].Equals('X');
        }

        private static bool CheckChinaID15(string ID) {
            Match m = Regex.Match(ID,@"\d{15}",RegexOptions.IgnoreCase);
            if(!m.Success) {
                return false;
            }
            if(!ChinaIDProvinceCodes.Contains(ID.Substring(0,2))) {
                return false;
            }
            CultureInfo zhCN = new CultureInfo("zh-CN",true);
            if(!DateTime.TryParseExact("19"+ID.Substring(6,6),"yyyyMMdd",zhCN,DateTimeStyles.None,out DateTime birthday)) {
                return false;
            }
            return birthday.In(new DateTime(1800,1,1),new DateTime(2000,1,1));
        }

        #endregion 权威校验身份证号码

        #region IP地址

        /// <summary>
        /// 校验IP地址的正确性，同时支持IPv4和IPv6
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <param name="isMatch">是否匹配成功，若返回true，则会得到一个Match对象，否则为null</param>
        /// <returns>匹配对象</returns>
        public static IPAddress MatchInetAddress(this string s,out bool isMatch) {
            isMatch=IPAddress.TryParse(s,out var ip);
            return ip;
        }

        /// <summary>
        /// 校验IP地址的正确性，同时支持IPv4和IPv6
        /// </summary>
        /// <param name="s">源字符串</param>
        /// <returns>是否匹配成功</returns>
        public static bool MatchInetAddress(this string s) {
            MatchInetAddress(s,out var success);
            return success;
        }

        /// <summary>
        /// IP地址转换成数字
        /// </summary>
        /// <param name="addr">IP地址</param>
        /// <returns>数字,输入无效IP地址返回0</returns>
        public static uint IPToID(this string addr) {
            if(!IPAddress.TryParse(addr,out var ip)) {
                return 0;
            }

            byte[] bInt = ip.GetAddressBytes();
            if(BitConverter.IsLittleEndian) {
                Array.Reverse(bInt);
            }

            return BitConverter.ToUInt32(bInt,0);
        }


        /// <summary>
        /// 判断IP地址在不在某个IP地址段
        /// </summary>
        /// <param name="input">需要判断的IP地址</param>
        /// <param name="begin">起始地址</param>
        /// <param name="ends">结束地址</param>
        /// <returns></returns>
        public static bool IpAddressInRange(this string input,string begin,string ends) {
            uint current = input.IPToID();
            return current>=begin.IPToID()&&current<=ends.IPToID();
        }

        #endregion IP地址

        #region 权威校验中国专利申请号/专利号

        /// <summary>
        /// 中国专利申请号（授权以后就是专利号）由两种组成
        /// 2003年9月30号以前的9位（不带校验位是8号），校验位之前可能还会有一个点，例如：00262311, 002623110 或 00262311.0
        /// 2003年10月1号以后的13位（不带校验位是12号），校验位之前可能还会有一个点，例如：200410018477, 2004100184779 或200410018477.9
        /// http://www.sipo.gov.cn/docs/pub/old/wxfw/zlwxxxggfw/hlwzljsxt/hlwzljsxtsyzn/201507/P020150713610193194682.pdf
        /// 上面的文档中均不包括校验算法，但是下面的校验算法没有问题
        /// </summary>
        /// <param name="patnum">源字符串</param>
        /// <returns>是否匹配成功</returns>
        public static bool MatchCNPatentNumber(this string patnum) {
            Regex patnumWithCheckbitPattern = new Regex(@"^
(?<!\d)
(?<patentnum>
    (?<basenum>
        (?<year>(?<old>8[5-9]|9[0-9]|0[0-3])|(?<new>[2-9]\d{3}))
        (?<sn>
            (?<patenttype>[12389])
            (?(old)\d{5}|(?(new)\d{7}))
        )
    )
    (?:
    \.?
    (?<checkbit>[0-9X])
    )?
)
(?!\d)
$",RegexOptions.IgnorePatternWhitespace|RegexOptions.IgnoreCase|RegexOptions.Multiline);
            Match m = patnumWithCheckbitPattern.Match(patnum);
            if(!m.Success) {
                return false;
            }
            bool isPatnumTrue = true;
            patnum=patnum.ToUpper().Replace(".","");
            if(patnum.Length==9||patnum.Length==8) {
                byte[] factors8 = new byte[8] { 2,3,4,5,6,7,8,9 };
                int year = Convert.ToUInt16(patnum.Substring(0,2));
                year+=(year>=85) ? (ushort)1900u : (ushort)2000u;
                if(year>=1985||year<=2003) {
                    int sum = 0;
                    for(byte i = 0;i<8;i++) {
                        sum+=factors8[i]*(patnum[i]-'0');
                    }
                    char checkbit = "0123456789X"[sum%11];
                    if(patnum.Length==9) {
                        if(checkbit!=patnum[8]) {
                            isPatnumTrue=false;
                        }
                    } else {
                        patnum+=checkbit;
                    }
                } else {
                    isPatnumTrue=false;
                }
            } else if(patnum.Length==13||patnum.Length==12) {
                byte[] factors12 = new byte[12] { 2,3,4,5,6,7,8,9,2,3,4,5 };
                int year = Convert.ToUInt16(patnum.Substring(0,4));
                if(year>=2003&&year<=DateTime.Now.Year) {
                    int sum = 0;
                    for(byte i = 0;i<12;i++) {
                        sum+=factors12[i]*(patnum[i]-'0');
                    }
                    char checkbit = "0123456789X"[sum%11];
                    if(patnum.Length==13) {
                        if(checkbit!=patnum[12]) {
                            isPatnumTrue=false;
                        }
                    } else {
                        patnum+=checkbit;
                    }
                } else {
                    isPatnumTrue=false;
                }
            } else {
                isPatnumTrue=false;
            }
            return isPatnumTrue;
        }

        /// <summary>
        /// 取字符串前{length}个字
        /// </summary>
        /// <param name="s"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public static string Take(this string s,int length) {
            return s.Length>length ? s.Substring(0,length) : s;
        }
        #endregion 权威校验中国专利申请号/专利号


        #region Base64编码
        /// <summary>
        /// Base64编码
        /// </summary>
        /// <param name="code">编码字符串</param>
        /// <param name="code_type">utf-8</param>
        /// <returns></returns>
        public static string EncodeBase64(this string code, string code_type = "utf-8")
        {
            string encode = "";
            byte[] bytes = Encoding.GetEncoding(code_type).GetBytes(code);
            try
            {
                encode = Convert.ToBase64String(bytes);
            }
            catch
            {
                encode = code;
            }
            return encode;
        }
        /// <summary>
        /// Base64解码
        /// </summary>
        /// <param name="code">解码字符串</param>
        /// <param name="code_type">utf-8</param>
        /// <returns></returns>
        public static string DecodeBase64(this string code, string code_type = "utf-8")
        {
            string decode = "";
            byte[] bytes = Convert.FromBase64String(code);
            try
            {
                decode = Encoding.GetEncoding(code_type).GetString(bytes);
            }
            catch
            {
                decode = code;
            }
            return decode;
        }
        #endregion
    }
}